#ifndef COMPILER_H
#define COMPILER_H

#include "ident.h"
#include "trees.h"
#include "program.h"

/*
 * Types available. The number '0' is valid as any type. These types
 * are only used by the compiler, when type checks are enabled. Compare with
 * the run-time types, named T_ interpret.h.
 */
#define TYPE_ANY        0	/* Will match any type */
#define TYPE_NOVALUE    1
#define TYPE_VOID       2
#define TYPE_NUMBER     3
#define TYPE_STRING     4
#define TYPE_OBJECT     5
#define TYPE_MAPPING    6
#define TYPE_REAL       7
#define TYPE_MASK	0xf

/*
 * These are or'ed in on top of the basic type.
 */
#define TYPE_MOD_ARRAY		0x0040        /* Pointer to a basic type */

#define NOVALUE_USED_FLAG        1024

#define LOOP_CONTEXT            0x1
#define LOOP_FOREACH            0x40
#define ARG_LIST		0x100

/*
 * Information for allocating a block that can grow dynamically
 * using realloc. That means that no pointers should be kept into such
 * an area, as it might be moved.
 */
typedef struct {
	char *block;
	int current_size;
	int max_size;
} mem_block_t;

/* NUMPAREAS ares are saved with the program code after compilation,
 * the rest are only temporary.
 */
#define A_PROGRAM		0	/* executable code */
#define A_FUNCTIONS             1
#define A_STRINGS		2	/* table of strings */
#define A_VAR_NAME		3
#define A_VAR_TYPE		4
#define A_LINENUMBERS		5	/* linenumber information */
#define A_FILE_INFO             6       /* start of file line nos */
#define A_INHERITS		7	/* table of inherited progs */
#define A_CLASS_DEF             8
#define A_CLASS_MEMBER          9
#define A_ARGUMENT_TYPES	10	/* */
#define A_ARGUMENT_INDEX	11	/* */
#define NUMPAREAS		12
#define A_CASES                 13      /* keep track of cases */
#define A_STRING_NEXT		14	/* next prog string in hash chain */
#define A_STRING_REFS		15	/* reference count of prog string */
#define A_INCLUDES		16	/* list of included files */
#define A_PATCH			17	/* for save_binary() */
#define A_FUNCTIONALS           18
#define A_FUNCTION_DEFS		19
#define A_VAR_TEMP	        20	/* table of variables */
#define NUMAREAS		21

#define TREE_MAIN               0
#define TREE_INIT               1
#define NUMTREES                2

#define CURRENT_PROGRAM_SIZE (prog_code - mem_block[A_PROGRAM].block)
#define UPDATE_PROGRAM_SIZE mem_block[A_PROGRAM].current_size = CURRENT_PROGRAM_SIZE

typedef struct compiler_temp_t {
	unsigned short flags;
	unsigned short offset;
	unsigned short function_index_offset;
	union {
		function_t *func;
		int index;
	} u;
} compiler_temp_t;

typedef struct {
	int runtime_index;
	ident_hash_elem_t *ihe;
} local_info_t;

#define realloc_mem_block(m) do { \
    mem_block_t *M = m; \
    M->max_size <<= 1; \
    M->block = realloc(M->block, M->max_size); \
} while (0)

#define add_to_mem_block(n, data, size) do { \
	mem_block_t *mbp = &mem_block[n]; \
	int Size = size; \
	\
	if (mbp->current_size + Size > mbp->max_size) { \
		do { \
			mbp->max_size <<= 1; \
		} while (mbp->current_size + Size > mbp->max_size); \
		\
		mbp->block = realloc(mbp->block, mbp->max_size); \
	} \
	memcpy(mbp->block + mbp->current_size, data, Size); \
	mbp->current_size += Size; \
} while (0)

#define COMP_TYPE(e, t) (!(e & TYPE_MOD_ARRAY) \
		&& (compatible[(unsigned char)e] & (1 << (t))))
#define IS_TYPE(e, t) (!(e & TYPE_MOD_ARRAY) \
		&& (is_type[(unsigned char)e] & (1 << (t))))

#define FUNCTION_TEMP(n) ((compiler_temp_t *)mem_block[A_FUNCTION_DEFS].block + (n))
#define FUNCTION_NEXT(n) (FUNCTION_TEMP(n)->next)
/* function_t from A_FUNCTIONS index */
#define FUNC(n) ((function_t *)mem_block[A_FUNCTIONS].block + (n))
/* function_t from full function index */
#define FUNCTION_DEF(n) FUNC(FUNCTION_TEMP(n)->u.index)
/* flags from full function index */
#define FUNCTION_FLAGS(n) (FUNCTION_TEMP(n)->flags)

#define VAR_TEMP(n) ((variable_t *)mem_block[A_VAR_TEMP].block + (n))
#define PROG_STRING(n)   (((char **)mem_block[A_STRINGS].block)[n])

extern int current_line;
extern char *current_file;

extern short compatible[];
extern short is_type[];
extern int exact_types;

extern unsigned short *comp_def_index_map, *func_index_map;

extern char *prog_code;
extern char *prog_code_max;

extern mem_block_t mem_block[];

extern parse_node_t *comp_trees[];

extern local_info_t *locals, *locals_ptr;
extern unsigned short *type_of_locals, *type_of_locals_ptr;

extern int locals_size;
extern int type_of_locals_size;
extern int current_number_of_locals;
extern int max_num_locals;

extern int num_parse_warning;
extern int num_parse_error;

/* in lexer.l */
int yylex();
void start_new_file(int);
void end_new_file();

void init_locals();

void free_all_local_names(int);
void deactivate_current_locals();
void reactivate_current_locals();
void pop_n_locals(int);
int add_local_name(char *, int);
void reallocate_locals();

int compatible_types(int, int);
int compatible_types2(int, int);

char *get_type_name(char *, char *, int);
void type_error(char *, int);
char *get_two_types(char *, char *, int, int);

int define_new_function(char *, int, int, int, int);
int define_new_variable(char *, int);
short store_prog_string(char *);
void free_prog_string(short);

int validate_function_call(int, parse_node_t *);
parse_node_t *validate_efun_call(int, parse_node_t *);

parse_node_t *promote_to_float(parse_node_t *);
parse_node_t *promote_to_int(parse_node_t *);
parse_node_t *do_promotions(parse_node_t *, int);

void yywarn(const char *, ...);
void yyerror(const char *, ...);

program_t * compile_file(int, char *);

char *allocate_in_mem_block(int, int);

#endif
